package com.sinog.core.util;

import com.sinog.core.utilbean.Constants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * @desc 身份证校验工具类
 * @author lzq
 * @date 2020-08-31 8:41 下午
 */
@Slf4j
public final class IdNumUtil {

    private static final Pattern COMPILE = Pattern.compile("");

    /**
     * 身份证脱敏
     * @param idnumOld 身份证
     * @return String
     */
    public static String deSensitiZation(String idnumOld) {
        if(Constants.Number.NUM_FIVE * Constants.Number.NUM_THREE == idnumOld.length()) {
            String substring = idnumOld.substring(0,6);
            String substring1 = idnumOld.substring(12,15);
            idnumOld = substring + "******" + substring1;
        }
        if(Constants.Number.NUM_SIX * Constants.Number.NUM_THREE == idnumOld.length()) {
            String substring = idnumOld.substring(0,8);
            String substring1 = idnumOld.substring(15,18);
            idnumOld = substring + "*******" + substring1;
        }
        return idnumOld;
    }

    /**
     * 校验身份证号
     * @param idNum 身份证号
     * @return boolean
     */
    public static boolean checkIdNum(String idNum) {
        if(StringUtils.isEmpty(idNum)) {
            return true;
        } else if(Constants.Number.NUM_FIVE * Constants.Number.NUM_THREE == idNum.length()) {
            return !check15(idNum);
        } else if(Constants.Number.NUM_SIX * Constants.Number.NUM_THREE == idNum.length()) {
            String[] split = COMPILE.split(idNum);
            return !check18(idNum) || !isTrueValidateCodeBy18IdCard(split);
        } else {
            return true;
        }
    }

    /**
     * 校验15位身份证号
     * @param idNum 身份证号
     * @return boolean
     */
    private static boolean check15(String idNum) {
        if(Constants.StrFinalValue.ZERO15.equals(idNum)) {
            return false;
        }
        String year = idNum.substring(6,8);
        String month = idNum.substring(8,10);
        String day = idNum.substring(10,12);
        Date date = new Date(Integer.parseInt(year),Integer.parseInt(month) - 1,Integer.parseInt(day));
        return !String.valueOf(date.getYear())
                      .equals(year) && date.getMonth() == Integer.parseInt(month) - 1 && date.getDay() == Integer.parseInt(day);
    }

    /**
     * 校验18位身份证号
     * @param idNum 身份证号
     * @return boolean
     */
    private static boolean check18(String idNum) {
        try {
            String year = idNum.substring(6,10);
            String month = idNum.substring(10,12);
            String day = idNum.substring(12,14);
            Date date = new Date(Integer.parseInt(year),Integer.parseInt(month) - 1,Integer.parseInt(day));
            return date.getYear() == Integer.parseInt(year) && date.getMonth() == Integer.parseInt(month) - 1 && date.getDate() == Integer.parseInt(day);
        } catch(NumberFormatException e) {
            log.error("身份证:{}校验失败！",idNum);
            return false;
        }
    }

    /**
     * 校验18位身份证是否真实
     * @param idNum 身份证号
     * @return boolean
     */
    private static boolean isTrueValidateCodeBy18IdCard(String[] idNum) {
        boolean b;
        try {
            // 加权因子
            int[] arrays = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2,1};
            // 身份证验证位值.10代表X
            int[] valideCode = {1,0,10,9,8,7,6,5,4,3,2};
            int sum = 0;
            if(Constants.StrFinalValue.SMALLX.equalsIgnoreCase(idNum[Constants.Number.NUM_SIX * Constants.Number.NUM_THREE - 1])) {
                idNum[Constants.Number.NUM_SIX * Constants.Number.NUM_THREE - 1] = "10";
            }
            for(int i = 0; Constants.Number.NUM_SIX * Constants.Number.NUM_THREE - 1 > i; i++) {
                sum += arrays[i] * Integer.parseInt(idNum[i]);
            }
            int valCodePosition = sum % 11;
            b = Integer.parseInt(idNum[Constants.Number.NUM_SIX * Constants.Number.NUM_THREE - 1]) == (valideCode[valCodePosition]);
        } catch(NumberFormatException n) {
            log.error("发生异常",n);
            return false;
        }
        return b;
    }
}